/*-------------------------------------------------------------------------
 *
 * dsa.h
 *	  动态共享内存区域。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *	  src/include/utils/dsa.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef DSA_H
#define DSA_H

#include "port/atomics.h"
#include "storage/dsm.h"

/* 用于区域的不透明类型。 */
struct dsa_area;
typedef struct dsa_area dsa_area;

/*
 * 如果此系统仅使用32位值作为size_t，那么请使用32位
 * 的DSA实现。这将限制可以创建的DSA数量
 * 显著低于整个4GB地址空间，因为
 * DSA指针必须编码一个段标识符和一个偏移量，但
 * 在实践中这不应该是一个重要的限制。
 *
 * 如果此系统不支持对64位值的原子操作，那么
 * 我们因缺乏其他选项而回退到32位dsa_pointer。
 *
 * 出于测试目的，可以定义USE_SMALL_DSA_POINTER以强制使用
 * 32位dsa_pointer，即使在能够支持64位
 * dsa_pointer的系统上。
 */
#if SIZEOF_SIZE_T == 4 || !defined(PG_HAVE_ATOMIC_U64_SUPPORT) || \
	defined(USE_SMALL_DSA_POINTER)
#define SIZEOF_DSA_POINTER 4
#else
#define SIZEOF_DSA_POINTER 8
#endif

/*
 * '相对指针'类型，指向动态共享区域分配的内存。
 * dsa_pointer值可以与其他进程共享，但必须在解引用之前
 * 转换为后端本地指针。请参见dsa_get_address。
 * 此外，还有原子版本和适当大小的原子操作。
 */
#if SIZEOF_DSA_POINTER == 4
typedef uint32 dsa_pointer;
typedef pg_atomic_uint32 dsa_pointer_atomic;
#define dsa_pointer_atomic_init pg_atomic_init_u32
#define dsa_pointer_atomic_read pg_atomic_read_u32
#define dsa_pointer_atomic_write pg_atomic_write_u32
#define dsa_pointer_atomic_fetch_add pg_atomic_fetch_add_u32
#define dsa_pointer_atomic_compare_exchange pg_atomic_compare_exchange_u32
#define DSA_POINTER_FORMAT "%08x"
#else
typedef uint64 dsa_pointer;
typedef pg_atomic_uint64 dsa_pointer_atomic;
#define dsa_pointer_atomic_init pg_atomic_init_u64
#define dsa_pointer_atomic_read pg_atomic_read_u64
#define dsa_pointer_atomic_write pg_atomic_write_u64
#define dsa_pointer_atomic_fetch_add pg_atomic_fetch_add_u64
#define dsa_pointer_atomic_compare_exchange pg_atomic_compare_exchange_u64
#define DSA_POINTER_FORMAT "%016" INT64_MODIFIER "x"
#endif

/* dsa_allocate_extended的标志。 */
#define DSA_ALLOC_HUGE		0x01	/* 允许大分配（> 1 GB） */
#define DSA_ALLOC_NO_OOM	0x02	/* 如果内存不足则不失败 */
#define DSA_ALLOC_ZERO		0x04	/* 零分配内存 */

/* 用于指示分配失败的dsa_pointer的哨兵值。 */
#define InvalidDsaPointer ((dsa_pointer) 0)

/* 检查dsa_pointer值是否有效。 */
#define DsaPointerIsValid(x) ((x) != InvalidDsaPointer)

/* 使用错误处理未初始化内存的分配。 */
#define dsa_allocate(area, size) \
	dsa_allocate_extended(area, size, 0)

/* 使用错误处理零初始化内存的分配。 */
#define dsa_allocate0(area, size) \
	dsa_allocate_extended(area, size, DSA_ALLOC_ZERO)

/*
 * 用于dsa_area句柄的类型。dsa_handle值可以与
 * 其他进程共享，以便它们可以附加到它们。这提供了一种
 * 与其他进程共享已分配存储的方法。
 *
 * 当前，dsa_area的句柄实现为支持此动态存储区域的
 * 第一个DSM段的dsm_handle，但客户端
 * 代码不应假设这是正确的。
 */
typedef dsm_handle dsa_handle;

extern dsa_area *dsa_create(int tranche_id);
extern dsa_area *dsa_create_in_place(void *place, size_t size,
									 int tranche_id, dsm_segment *segment);
extern dsa_area *dsa_attach(dsa_handle handle);
extern dsa_area *dsa_attach_in_place(void *place, dsm_segment *segment);
extern void dsa_release_in_place(void *place);
extern void dsa_on_dsm_detach_release_in_place(dsm_segment *, Datum);
extern void dsa_on_shmem_exit_release_in_place(int, Datum);
extern void dsa_pin_mapping(dsa_area *area);
extern void dsa_detach(dsa_area *area);
extern void dsa_pin(dsa_area *area);
extern void dsa_unpin(dsa_area *area);
extern void dsa_set_size_limit(dsa_area *area, size_t limit);
extern size_t dsa_minimum_size(void);
extern dsa_handle dsa_get_handle(dsa_area *area);
extern dsa_pointer dsa_allocate_extended(dsa_area *area, size_t size, int flags);
extern void dsa_free(dsa_area *area, dsa_pointer dp);
extern void *dsa_get_address(dsa_area *area, dsa_pointer dp);
extern void dsa_trim(dsa_area *area);
extern void dsa_dump(dsa_area *area);

#endif							/* DSA_H */
